using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
using System.Collections.Concurrent;
using System.Threading;
using System.Diagnostics;
using static YiNing.UI.Config.Enums;

namespace YiNing.UI.Controls
{
    public partial class Wafermap : UserControl
    {
        #region 参数

        private bool _showSettings = true;

        /// <summary>
        /// Die鼠标点击事件
        /// </summary>
        public event EventHandler<Die> OnDieClick; //定义一个委托类型的事件
        public event EventHandler<Die[,]> OnMappingUpdate; //定义一个委托类型的事件 
        private String tooSmallString = "TOO SMALL";
        private int _DieAlpha = 150;

        /// <summary>
        /// 是否可交互
        /// </summary>
        [Description("是否显示设置界面")]
        [DefaultValue(true)]
        public bool ShowSettings
        {
            get { return _showSettings; }
            set
            {
                _showSettings = value;
                if (_showSettings) darkSettionPanel.Visible = true;
                else darkSettionPanel.Visible = false;
            }
        }

        #region 拖动

        private bool DragMode = false;
        private DarkLabel darkLabel5;
        private DarkLabel darkLabel6;
        private CheckBox cbMouseEnable;
        private ToolTip toolTip1;
        private IContainer components;
        private Point DragStartPoint;
        #endregion

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x0014) // 禁掉清除背景消息
                return;
            base.WndProc(ref m);
        }
        public String TooSmallString
        {
            get { return tooSmallString; }
            set { tooSmallString = value; }
        }

        private String noDataString = "NO DATA";

        [Description("芯片的透明度")]
        [DefaultValue(150)]
        public int DieAlpha
        {
            get { return _DieAlpha; }
            set
            {
                _DieAlpha = value;
                Invalidate();
            }
        }

        private bool _IsShowTooltip = true;
        [Description("鼠标移动显示坐标,只有在晶圆X和Y方向上数量都小于100时才会生效")]
        [DefaultValue(true)]
        public bool IsShowTooltip
        {
            get { return _IsShowTooltip; }
            set
            {
                _IsShowTooltip = value;
            }
        }

        private string _TooltipFormat = "Y:{0} X:{1}";
        [Description("鼠标移动显示坐标格式")]
        [DefaultValue("Y:{0} X:{1}")]
        public string TooltipFormat
        {
            get { return _TooltipFormat; }
            set
            {
                _TooltipFormat = value;
            }
        }

        //private bool _IsShowAlph= true;
        //[Description("坐标显示字母,只有在晶圆X和Y方向上数量小于36时才会生效")]
        //[DefaultValue(true)]
        //public bool IsShowAlph
        //{
        //    get { return _IsShowAlph; }
        //    set
        //    {
        //        _IsShowAlph = value;
        //    }
        //}


        public String NoDataString
        {
            get { return noDataString; }
            set { noDataString = value; }
        }

        private int _SelectX = 0, _SelectY = 0;
        private Die _SelectOneDie;
        private Die[] _SelectRegionDiagonalDie;
        private Die _selectStartDie, _selectEndDie; // 这两个是多选die的开始和结束die
        private bool SelectMode = false; //是否是选中模式,鼠标up就为false
        private bool _SelectMultiple = true; //是否是选中模式,鼠标up就为false
        private bool _RemoveIncompleteDie = false; //去除边沿不完整的die
        private int _ExcludeEdgeNum = 0; //边沿排除个数
        private Die[,] dataset;
        private bool _DirectionOnlyNgDie = false;

        private int _DieIntervalX = 0;
        private int _DieIntervalY = 0;

        private int _DieAllNum = 0;
        private int _DieOkNum = 0;
        private int _DieNgNum = 0;

        private TraitType _NotcheOrFlat = TraitType.Notch;

        /// <summary>
        /// 类型
        /// </summary>
        public TraitType NotcheOrFlat
        {
            get { return _NotcheOrFlat; }
            set { _NotcheOrFlat = value; }
        }

        /// <summary>
        /// 所有芯片总个数
        /// </summary>
        public int DieAllNum
        {
            get { return _DieAllNum; }
            set { _DieAllNum = value; }
        }

        /// <summary>
        /// 良品芯片总个数
        /// </summary>
        public int DieOkNum
        {
            get { return _DieOkNum; }
            set { _DieOkNum = value; }
        }

        /// <summary>
        /// 缺陷芯片总个数
        /// </summary>
        public int DieNgNum
        {
            get { return _DieNgNum; }
            set { _DieNgNum = value; }
        }

        [Description("获取X方向上的间距")]
        public int DieIntervalX
        {
            get { return _DieIntervalX; }
        }
        [Description("获取Y方向上的间距")]
        public int DieIntervalY
        {
            get { return _DieIntervalY; }
        }

        /// <summary>
        /// 是否多选
        /// </summary>
        [Description("箭头操作只对NG芯片有效")]
        [DefaultValue(false)]
        public bool DirectionOnlyNgDie
        {
            get { return _DirectionOnlyNgDie; }
            set
            {
                _DirectionOnlyNgDie = value;
            }
        }
        /// <summary>
        /// 是否多选
        /// </summary>
        [Description("是否多选")]
        [DefaultValue(true)]
        public bool SelectMultiple
        {
            get { return _SelectMultiple; }
            set
            {
                _SelectMultiple = value;
            }
        }

        [Description("边沿排除的个数")]
        [DefaultValue(0)]
        public int ExcludeEdgeNum
        {
            get { return _ExcludeEdgeNum; }
            set
            {
                _ExcludeEdgeNum = value;

                for (int x = 0; x < dataset.GetLength(0); x++)
                {
                    for (int y = 0; y < dataset.GetLength(1); y++)
                    {
                        dataset[x, y].IsEdge = false;
                        dataset[x, y].Enabled = false;
                    }
                }

                Invalidate();
            }
        }

        [Description("是否去除不完整的区域")]
        [DefaultValue(false)]
        public bool RemoveIncompleteDie
        {
            get { return _RemoveIncompleteDie; }
            set
            {
                _RemoveIncompleteDie = value;
                Invalidate();
            }
        }


        /// <summary>
        /// 设置单个选中Die的X
        /// </summary>
        [Description("设置单个选中Die的X")]
        public int SelectX
        {
            get { return _SelectX; }
            set
            {
                if (dataset != null && dataset.Length > 0 && value >= 0 && value < dataset.GetLength(0)) _SelectOneDie = dataset[value, _SelectY];
                else return;
                var pre = _SelectOneDie != null ? _SelectOneDie : null;
                updateTDLR(pre);
                _SelectOneDie = dataset[value, _SelectY];
                if (_SelectOneDie.IsEdge) return;
                _SelectX = value;
                updateDie(pre, _SelectOneDie, true);
                if (OnDieClick != null) OnDieClick(this, _SelectOneDie);
            }
        }
        /// <summary>
        /// 设置单个选中Die的Y
        /// </summary>
        [Description("设置单个选中Die的Y")]
        public int SelectY
        {
            get { return _SelectY; }
            set
            {
                if (dataset != null && dataset.Length > 0 && value >= 0 && value < dataset.GetLength(1)) _SelectOneDie = dataset[_SelectX, value]; else return;
                var pre = _SelectOneDie != null ? _SelectOneDie : null;
                updateTDLR(pre);
                _SelectOneDie = dataset[_SelectX, value];
                if (_SelectOneDie.IsEdge) return;
                _SelectY = value;
                updateDie(pre, _SelectOneDie, true);
                if (OnDieClick != null) OnDieClick(this, _SelectOneDie);
            }
        }

        [Description("数据")]
        public Die[,] Dataset
        {
            get { return dataset; }
            set
            {
                _DieIntervalX = 0;
                _DieIntervalY = 0;
                SelectX = 0;
                SelectY = 0;
                previousX = -1;
                previousY = -1;
                dataset = null;
                GC.Collect();
                SelectOneDie = null;
                dataset = value;
                Invalidate();
                GetDiesStatistic();
                CalDieInterval();
                CalMappingOffsetXY();
            }
        }

        private int _OffsetX = 0;
        [Description("获取X方向的有效die偏移")]
        public int OffsetX
        {
            get { return _OffsetX; }
        }
        private int _OffsetY = 0;
        [Description("获取X方向的有效die偏移")]
        public int OffsetY
        {
            get { return _OffsetY; }
        }

        /// <summary>
        /// 获取偏移xy
        /// </summary>
        private void CalMappingOffsetXY()
        {
            if (dataset == null) return;
            int minX, minY;
            minX = dataset.GetLength(0) - 1; minY = dataset.GetLength(1) - 1;

            for (int y = 0; y < dataset.GetLength(1) - 1; y++)
            {
                for (int x = 0; x < dataset.GetLength(0) - 1; x++)
                {
                    if (!dataset[x, y].IsEdge && dataset[x, y].XIndex < minX) minX = dataset[x, y].XIndex;
                    if (!dataset[x, y].IsEdge && dataset[x, y].YIndex < minY) minY = dataset[x, y].YIndex;
                }
            }
            _OffsetX = minX;
            _OffsetY = minY;
        }

        /// <summary>
        /// 计算mapping的x，y方向的间距
        /// </summary>
        private void CalDieInterval()
        {
            #region 计算DieXY方向的间距
            bool findX = false;
            bool findY = false;
            if (dataset == null) return;
            for (int x = 0; x < dataset.GetLength(0) - 1; x++)
            {
                if (findX) break;
                for (int y = 0; y < dataset.GetLength(1) - 1; y++)
                {
                    int line1X = 0, nextLineX = 0;
                    if (!dataset[x, y].IsEdge && dataset[x, y].YPluse > 0)
                    {
                        line1X = dataset[x, y].XPluse;
                    }
                    if (line1X == 0) continue;

                    for (int y2 = 0; y2 < dataset.GetLength(0) - 1; y2++)
                    {
                        if (!dataset[x + 1, y2].IsEdge && dataset[x + 1, y2].YPluse > 0)
                        {
                            nextLineX = dataset[x + 1, y2].XPluse;
                        }
                        if (nextLineX == 0) continue; else break;
                    }
                    _DieIntervalX = Math.Abs(nextLineX - line1X);
                    findX = true;
                }
            }

            for (int y = 0; y < dataset.GetLength(1) - 1; y++)
            {
                if (findY) break;
                for (int x = 0; x < dataset.GetLength(0) - 1; x++)
                {
                    //if (!dataset[x, y].IsEdge && !dataset[x + 1, y].IsEdge)
                    //{
                    //    _DieIntervalX = Math.Abs(dataset[x, y].XPluse - dataset[x + 1, y].XPluse);
                    //}
                    int line1Y = 0, nextLineY = 0;
                    if (!dataset[x, y].IsEdge && dataset[x, y].YPluse > 0)
                    {
                        line1Y = dataset[x, y].YPluse;
                    }
                    if (line1Y == 0) continue;

                    for (int x2 = 0; x2 < dataset.GetLength(0) - 1; x2++)
                    {
                        if (!dataset[x2, y + 1].IsEdge && dataset[x2, y + 1].YPluse > 0)
                        {
                            nextLineY = dataset[x2, y + 1].YPluse;
                        }
                        if (nextLineY == 0) continue; else break;
                    }
                    _DieIntervalY = Math.Abs(nextLineY - line1Y);
                    findY = true;
                }
            }
            Console.WriteLine(string.Format("DieIntervalX:{0} DieIntervalY:{1}", DieIntervalX, DieIntervalY));
            #endregion
            //#region 填充Die间距位置坐标
            //for (int y = 0; y < dataset.GetLength(1); y++)
            //{
            //    for (int x = 0; x < dataset.GetLength(0); x++)
            //    {
            //        if (dataset[x, y].XPluse == 0)
            //        {
            //            dataset[x, y].XPluse = dataset[x, y].XPluse
            //        }
            //    }
            //}
            //#endregion
        }

        /// <summary>
        /// 选中单个die
        /// </summary>
        [Description("选中单个die")]
        public Die SelectOneDie
        {
            get { return _SelectOneDie; }
            set
            {
                var pre = _SelectOneDie;
                _SelectOneDie = value;
                updateDie(pre, _SelectOneDie, false);
            }
        }

        /// <summary>
        /// 多选区域的对角线2点，会自动计算该点属于区域的那个顶点,Get获取的可能就不是最终传入的两个点，最终保存的是左上角点和右下角点
        /// </summary>
        [Description("多选区域的对角线2点，会自动计算该点属于区域的那个顶点,Get获取的可能就不是最终传入的两个点，最终保存的是左上角点和右下角点")]
        public Die[] SelectRegionDiagonalDie
        {
            get { return _SelectRegionDiagonalDie; }
            set
            {
                if (value != null && value.Length >= 2)
                {
                    _selectStartDie = value[0];
                    _selectEndDie = value[1];
                    DrawSelectDies();
                }
            }
        }


        private int translation_x = 0;

        public int TranslationX
        {
            get { return translation_x; }
            set { translation_x = value; }
        }

        private int translation_y = 0;

        public int TranslationY
        {
            get { return translation_y; }
            set { translation_y = value; }
        }

        private int rotation;

        /// <summary>
        /// 旋转角度可能会有问题，未测试
        /// </summary>
        [Description("旋转角度可能会有问题，未测试")]
        public int Rotation
        {
            get { return rotation; }
            set
            {
                if (value < 0) value = 360 + value;
                if (value % 90 == 0 && value >= 0 && value < 360)
                    rotation = value;
                else
                    throw new ArgumentException("Rotation has to be 0, 90, 180 or 270 degrees (Is " + value + ")");
            }
        }


        private float zoom;

        public float Zoom
        {
            get { return zoom; }
            set { zoom = value; }
        }
        private int notchLocation = 0;


        /// <summary>
        /// 缺角位置
        /// </summary>
        [Description("缺角位置")]
        public int Notchlocation
        {
            get { return notchLocation; }
            set
            {
                if (value == 360) value = 0;
                else if (value < 0) value = 360 + value;
                if (value % 90 == 0 && value >= 0 && value <= 270)
                    notchLocation = value;
                else
                    throw new ArgumentException("NotchLocation has to be 0, 90, 180 or 270 degrees (Is " + value + ")");
            }
        }

        public int tempX = -1, tempY = -1;
        private DarkLabel darkLabel1;
        private DarkSectionPanel darkSettionPanel;
        private DarkLabel darkLabel2;
        private DarkLabel darkLabel4;
        private DarkLabel darkLabel3;

        /// <summary>
        /// 显示进度
        /// </summary>
        /// <param name="isZ">z字形显示</param>

        public void ShowProgress(bool isZ = true)
        {
            if (Colors.Length < 2) throw new Exception("colors必须大于等于2个颜色");
            if (tempX == -1 && tempY == -1)
            {
                for (int y = 0; y < dataset.GetLength(1); y++)
                {
                    for (int x = 0; x < dataset.GetLength(0); x++)
                    {
                        if (!dataset[x, y].IsEdge)
                        {
                            tempX = x; tempY = y; goto fina;
                        }
                    }
                }
            }
            else
            {
                if (isZ && tempY % 2 == 0)
                {
                    tempX--;
                }
                else
                {
                    tempX++;
                }
                if (tempX <= 0 || tempX >= dataset.GetLength(0))
                {
                    return;
                }
                if (dataset[tempX, tempY].IsEdge)
                {
                    tempY++;
                    tempX = (isZ && tempY % 2 == 0) ? dataset.GetLength(0) - 1 : 0;
                    #region 搜寻这行的第一个
                    while (dataset[tempX, tempY].IsEdge)
                    {
                        if (isZ && tempY % 2 == 0) tempX--; else tempX++;
                    }
                    #endregion
                }

            }
        fina:
            dataset[tempX, tempY].ColorIndex = 1;
        }

        /// <summary>
        /// 获取晶圆的飞拍行数据
        /// </summary>
        /// <returns></returns>
        public List<FlyLineWafer> GetWaferFlyPoints(Point waferCenter, out ConcurrentQueue<Die> dies, bool isZ = true)
        {
            dies = new ConcurrentQueue<Die>();
            var flys = new List<FlyLineWafer>();
            for (int y = 0; y < dataset.GetLength(1); y++)
            {
                FlyLineWafer flyPoint = new FlyLineWafer(-20181121, -20181121, -20181121);
                var onlyLine = new List<Die>();
                int maxX = -20181121;
                for (int x = 0; x < dataset.GetLength(0); x++) // 一次循环直接计算最小最大的区间范围
                {
                    if (!dataset[dataset.GetLength(0) - 1 - x, y].IsEdge && maxX == -20181121) maxX = dataset.GetLength(0) - 1 - x;
                    if (!dataset[x, y].IsEdge || x <= maxX) // #这里判断过滤了中间空白的不是芯片的区域，要加个机制把两个isedge=false中间的都加上！！！那么等差模式才可以正常使用，不然就测试FIFO的稳定性把
                    {
                        if (isZ && y % 2 == 0)
                        {
                            dies.Enqueue(dataset[x, y]);
                        }
                        else
                        {

                            onlyLine.Add(dataset[x, y]);
                        }
                        if (flyPoint.StartX == -20181121) flyPoint.StartX = dataset[x, y].OffsetWaferCenterXPulse + waferCenter.X;
                        flyPoint.EndX = dataset[x, y].OffsetWaferCenterXPulse + waferCenter.X;
                        flyPoint.Y = dataset[x, y].OffsetWaferCenterYPulse + waferCenter.Y;
                    }
                    else if (x > maxX && maxX != -20181121) break;
                }
                if (!(isZ && y % 2 == 0))
                {
                    for (int i = onlyLine.Count - 1; i >= 0; i--)
                    {
                        dies.Enqueue(onlyLine[i]);
                    }
                }
                flyPoint.LineId = y;
                if (flyPoint.StartX != -20181121 && flyPoint.EndX != -20181121)
                    flys.Add(flyPoint);
            }
            return flys;
        }

        private Color[] colors;

        /// <summary>
        /// 所有颜色
        /// </summary>
        [Description("所有颜色")]
        public Color[] Colors
        {
            get { return colors; }
            set { colors = value; }
        }

        private bool interactive = true;
        /// <summary>
        /// 是否可交互
        /// </summary>
        [Description("是否可交互")]
        [DefaultValue(true)]
        public bool Interactive
        {
            get { return interactive; }
            set
            {
                interactive = value;
                registerEvents();
            }
        }

        #endregion

        protected override CreateParams CreateParams
        {
            get
            {
                var parms = base.CreateParams;
                parms.Style &= ~0x02000000; // Turn off WS_CLIPCHILDREN 
                return parms;
            }
        }
        public Wafermap()
        {
            zoom = 1f;
            InitializeComponent();
            SetControlPre();

            this.UpdateStyles();

            if (!IsDesignMode())
            {
                setupDefaultColors();
                registerEvents();
            }
        }

        /// <summary>
        /// 设置控件显示的缓冲等
        /// </summary>
        private void SetControlPre()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);//控件忽略窗口消息，减少闪烁
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);//控件将首先绘制到缓冲区而不是屏幕，减少闪烁
            this.SetStyle(ControlStyles.ResizeRedraw, true);//当控件大小发生变化时就重新绘制
            this.SetStyle(ControlStyles.Selectable, true);//控件可以接受焦点
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);//支持模拟透明度
            this.SetStyle(ControlStyles.UserPaint, true);//使用自定义绘制方式
            this.SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲
            this.SetStyle(ControlStyles.CacheText, true); 
        }

        public bool IsDesignMode()
        {
            bool returnFlag = false;

#if DEBUG
            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            {
                returnFlag = true;
            }
            else if (Process.GetCurrentProcess().ProcessName == "devenv")
            {
                returnFlag = true;
            }
#endif

            return returnFlag;
        }

        public void ReFresh()
        {
            Invalidate();
        }
        private void setupDefaultColors()
        {
            // Just some sample colors to get started
            colors = new Color[255];
            colors[0] = Color.FromArgb(_DieAlpha, Color.Green);
            colors[1] = Color.FromArgb(_DieAlpha, Color.Red);
            colors[2] = Color.FromArgb(_DieAlpha, Color.Yellow);
            colors[3] = Color.FromArgb(_DieAlpha, Color.Blue);
            colors[4] = Color.FromArgb(_DieAlpha, Color.Orange);
            colors[5] = Color.FromArgb(_DieAlpha, Color.Magenta);
            colors[6] = Color.FromArgb(_DieAlpha, Color.DarkBlue);
            colors[7] = Color.FromArgb(_DieAlpha, Color.Pink);
            colors[50] = Color.FromArgb(_DieAlpha, Color.Black);
        }

        private void Wafermap_Load(object sender, EventArgs e)
        {
            //this.Dock = DockStyle.Fill;
        }

        private bool isScaled;

        public bool IsScaled
        {
            get { return isScaled; }

        }

        private int scaleFactor;

        public int ScaleFactor
        {
            get { return scaleFactor; }
        }


        // We need some globals to be available for calculations
        RectangleF boundingBox_;
        SizeF dieSize_;


        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = SmoothingMode.HighSpeed;
            // set rotation
            e.Graphics.RotateTransform((float)rotation);
            if (rotation != 0)
            {
                // When we rotate, we also have to translate
                switch (rotation)
                {
                    case 90:
                        e.Graphics.TranslateTransform(0, -boundingBox_.Width);
                        break;
                    case 180:
                        e.Graphics.TranslateTransform(-boundingBox_.Width, -boundingBox_.Height);
                        break;
                    case 270:
                        e.Graphics.TranslateTransform(-boundingBox_.Height, 0);
                        break;
                }
            }
            // set additional translation
            e.Graphics.TranslateTransform(translation_x, translation_y);

            // 使用抗锯齿
            //e.Graphics.SmoothingMode = SmoothingMode.HighSpeed;

            // Here comes everything that has to be calculated on each resize/redraw
            // Just do this calculations once
            // Let's find the best Size for the outline
            float w = this.Width * zoom;
            float h = this.Height * zoom;

            float size = w < h ? w : h;
            // Wafersize is size-2 because we're not drawing the first and the last pixels
            SizeF wafersize = new SizeF(size - 2, size - 2);
            PointF starting = new PointF((w - size) / 2f, (h - size) / 2f);
            RectangleF boundingBox = new RectangleF(starting, wafersize);
            boundingBox_ = boundingBox;
            // Create graphics path.
            GraphicsPath clipPath = new GraphicsPath();
            clipPath.AddEllipse(boundingBox);
            //// Set clipping region to path.
            e.Graphics.SetClip(clipPath, CombineMode.Replace);
            //clipPath = new GraphicsPath();
            //clipPath.AddRectangle(new RectangleF(new PointF(boundingBox.Left, boundingBox.Bottom -10), new SizeF(boundingBox.Width, boundingBox.Height)));
            //e.Graphics.SetClip(clipPath, CombineMode.Exclude);


            // Let's calculate everything needed for drawing the dies
            if (dataset != null && dataset.Length > 0)
            {
                int maxX = dataset.GetLength(0);
                int maxY = dataset.GetLength(1);
                float sizeX = boundingBox.Width / (float)maxX;
                float sizeY = boundingBox.Height / (float)maxY;

                int every = 1;

                // If dieSizeX or dieSizeY is less then 2 pixels
                // take only every nth die
                while (sizeX <= 2 || sizeY <= 2)
                {
                    every = every * 2;
                    sizeX = boundingBox.Width / (float)(maxX / every);
                    sizeY = boundingBox.Height / (float)(maxY / every);
                }
                SizeF dieSize = new SizeF(sizeX, sizeY);
                dieSize_ = dieSize;
                // If every != 1 we recalculate the input data
                // Otherwise we pass the original dataset
                // Caveat: We must not overwrite the original dataset ;)
                if (every > 1)
                {
                    //Create a new dataset
                    // Get the highest bin code in x / y to x/ y + every as result for x / y

                    //First set the property

                    isScaled = true;
                    scaleFactor = every;
                    drawCircle(e.Graphics, boundingBox);
                    //drawDies(e.Graphics, boundingBox, WafermapTools.scaleArray(dataset, every), dieSize);
                    //Print "Too small" message
                    FontFamily myFontFamily = new FontFamily("Arial");
                    Font myFont = new Font(myFontFamily,
                       20,
                       FontStyle.Bold,
                       GraphicsUnit.Pixel);

                    e.Graphics.DrawString("请放大显示完整图谱", myFont, new SolidBrush(Color.White), new PointF(w / 2 - 100, h / 2));

                }
                else
                {
                    // Properties
                    isScaled = false;
                    scaleFactor = 1;

                    // Simply draw the die
                    drawDies(e.Graphics, boundingBox, dataset, dieSize);
                }
            }
            else
            {
                drawCircle(e.Graphics, boundingBox);
                // Display "No Data" message
                FontFamily myFontFamily = new FontFamily("宋体");
                Font myFont = new Font(myFontFamily,
                   10,
                   FontStyle.Bold);

                e.Graphics.DrawString(noDataString, myFont, new SolidBrush(Color.DimGray), new PointF(w / 2 - 25, h / 2));
            }
            drawNotch(e.Graphics, boundingBox, notchLocation);

            //e.Graphics.ScaleTransform(2, 2);
        }

        // Try to reuse - only instantiated once
        SolidBrush waferFillbrush = new SolidBrush(Color.DimGray);
        Pen blackPen = new Pen(Color.Black);
        //底部的缺口
        SolidBrush notchFillBrush = new SolidBrush(Color.White);
        /// <summary>
        /// 绘画园
        /// </summary>
        /// <param name="g"></param>
        /// <param name="boundingBox"></param>
        private void drawCircle(Graphics g, RectangleF boundingBox)
        {
            //g.FillPie(Brushes.Pink, new Rectangle(-10, 20, this.Width, this.Height), 180, 180);//绘制半圆
            g.FillEllipse(waferFillbrush, boundingBox);
            //g.DrawEllipse(blackPen, boundingBox);
        }

        /// <summary>
        /// 绘画底部的缺口
        /// </summary>
        /// <param name="g"></param>
        /// <param name="boundingBox"></param>
        /// <param name="location"></param>
        private void drawNotch(Graphics g, RectangleF boundingBox, int location)
        {
            try
            {
                /*
                 *  //在晶圆上画凹口（物理性质）以对准。可以是0、90、180、270度
                    //从0开始° 底部（逆时针）
                    //形状固定在切割圆上
                 */
                float size = boundingBox.Width < boundingBox.Height ? boundingBox.Width : boundingBox.Height;
                int start = 0;
                int end = 180;
                size = size * 0.05f;
                // 计算切口的位置
                // 180°
                float x = boundingBox.X + (boundingBox.Width / 2f) - (size / 2f);
                float y = boundingBox.Y - (size / 2f);
                switch (location)
                {
                    case 0:
                        //if (dataset != null && dataset.GetLength(1) > 100) size = size * 0.02f;
                        y = boundingBox.Y + boundingBox.Height - (size / 2f);
                        end = -180;
                        if (NotcheOrFlat == TraitType.Flat)
                        {
                            notchFillBrush = new SolidBrush(this.BackColor);
                            g.FillRectangle(notchFillBrush, 0, y, Width, size);
                        }
                        break;
                    case 90:
                        //if (dataset != null && dataset.GetLength(0) > 100) size = size * 0.04f;
                        x = boundingBox.X - (size / 2f);
                        y = boundingBox.Y + (boundingBox.Height / 2f) - (size / 2f);
                        start = 90;
                        end = -180;
                        if (NotcheOrFlat == TraitType.Flat)
                        {
                            notchFillBrush = new SolidBrush(this.BackColor);
                            g.FillRectangle(notchFillBrush, x, 0, size, Height);
                        }
                        break;
                    case 270:
                        //if (dataset != null && dataset.GetLength(1) > 100) size = size * 0.02f;
                        x = boundingBox.X + boundingBox.Width - (size / 2f);
                        y = boundingBox.Y + (boundingBox.Height / 2f) - (size / 2f);
                        start = 90;
                        end = 180;
                        if (NotcheOrFlat == TraitType.Flat)
                        {
                            notchFillBrush = new SolidBrush(this.BackColor);
                            g.FillRectangle(notchFillBrush, x, 0, size, Height);
                        }
                        break;
                }

                if (NotcheOrFlat == TraitType.Notch)
                {
                    g.FillPie(notchFillBrush, x, y, size, size, start, end);
                }
            }
            catch (Exception er) { }
        }
        Pen dieOutlinePen = new Pen(Color.White);
        /// <summary>
        /// 绘画单个die的样式和选中的die样式
        /// </summary>
        /// <param name="g"></param>
        /// <param name="boundingBox"></param>
        /// <param name="data"></param>
        /// <param name="selectDies"></param>
        /// <param name="dieSize"></param>
        private void drawDies(Graphics g, RectangleF boundingBox, Die[,] data, SizeF dieSize)
        {
            g.SmoothingMode = SmoothingMode.HighSpeed;
            if (!IsHandleCreated) return;
            for (int x = 0; x < data.GetLength(0); x++)
            {
                for (int y = 0; y < data.GetLength(1); y++)
                {
                    Color fill = Color.FromArgb(_DieAlpha, colors[data[x, y].ColorIndex]);
                    PointF position = new PointF(boundingBox.X + (float)x * dieSize.Width, boundingBox.Y + (float)y * dieSize.Height);
                    RectangleF die = new RectangleF(position, dieSize);

                    //g.DrawString("134")
                    //判断4个角是否在显示范围内，不在的话不显示
                    if (data[x, y].IsEdge)
                    {
                        data[x, y].Enabled = false;
                        //g.FillRectangle(new SolidBrush(Color.FromArgb(0, Color.DimGray)), die);
                        g.DrawRectangle(dieOutlinePen, die.X, die.Y, die.Width, die.Height);
                    }
                    else
                    {
                        data[x, y].Enabled = true;
                        g.FillRectangle(new SolidBrush(fill), die);
                        g.DrawRectangle(dieOutlinePen, die.X, die.Y, die.Width, die.Height);
                    }
                }
            }
            //dataset = data;
            //if (savePath != "")
            //{
            //    string aa = JsonConvert.SerializeObject(visibleDataset);
            //    File.WriteAllText(savePath, aa);
            //    VisibleDatasetSavePath = "";
            //}
            #region 绘画选中die的样式
            if (isMouseHoldMove &&  _selectStartDie != null && _selectEndDie != null) // 多个die
            {
                Die[] dies = GetLeftTopAndRightBottomDie(_selectStartDie, _selectEndDie);
                PointF positionSelect = new PointF(boundingBox_.X + (float)dies[0].XIndex * dieSize_.Width - 1, boundingBox_.Y + (float)dies[0].YIndex * dieSize_.Height - 1);
                RectangleF dieSelect = new RectangleF(positionSelect, new SizeF((dies[1].XIndex - dies[0].XIndex + 1) * dieSize_.Width + 2, (dies[1].YIndex - dies[0].YIndex + 1) * dieSize_.Height + 2));

                ////四个边角只要右一个不在里面就直接返回不绘制
                //if (!g.IsVisible(positionSelect.X, positionSelect.Y) || !g.IsVisible(positionSelect.X, positionSelect.Y + dieSize.Height) || !g.IsVisible(positionSelect.X + dieSize.Width, positionSelect.Y) || !g.IsVisible(positionSelect.X + dieSize.Width, positionSelect.Y + dieSize.Height))
                //{
                //    return;
                //}

                g.DrawRectangle(new Pen(Color.White, 4), dieSelect.X + 2, dieSelect.Y + 2, dieSelect.Width - 4, dieSelect.Height - 4);
                g.DrawRectangle(new Pen(Color.Black, 4), dieSelect.X - 2, dieSelect.Y - 2, dieSelect.Width + 4, dieSelect.Height + 4);
            }
            else if (_SelectOneDie != null && !_SelectOneDie.IsEdge) //单个die选中
            {
                // 放到for循环外主要是为了解决右边和下边的边框被重绘了造成部分白色区域
                //Color fillSelect = Color.FromArgb(255, colors[_SelectOneDie.ColorIndex]);
                PointF positionSelect = new PointF(boundingBox_.X + (float)_SelectX * dieSize_.Width - 1, boundingBox_.Y + (float)_SelectY * dieSize_.Height - 1);
                RectangleF dieSelect = new RectangleF(positionSelect, new SizeF(dieSize_.Width + 2, dieSize_.Height + 2));
                ////四个边角只要右一个不在里面就直接返回不绘制
                //if (!g.IsVisible(positionSelect.X, positionSelect.Y) || !g.IsVisible(positionSelect.X, positionSelect.Y + dieSize.Height) || !g.IsVisible(positionSelect.X + dieSize.Width, positionSelect.Y) || !g.IsVisible(positionSelect.X + dieSize.Width, positionSelect.Y + dieSize.Height))
                //{
                //    return;
                //}

                //g.FillRectangle(new SolidBrush(fillSelect), dieSelect);
                // 这里是重绘选中的芯片
                g.DrawRectangle(new Pen(Color.White, 4), dieSelect.X + 2, dieSelect.Y + 2, dieSelect.Width - 4, dieSelect.Height - 4);
                g.DrawRectangle(new Pen(Color.Black, 4), dieSelect.X - 2, dieSelect.Y - 2, dieSelect.Width + 4, dieSelect.Height + 4);
            }
            #endregion
            //Invalidate();
        }

        /// <summary>
        /// 获取所有的芯片个数
        /// </summary>
        /// <returns></returns>
        public void GetDiesStatistic()
        {
            DieAllNum = 0;
            DieOkNum = 0;
            DieNgNum = 0;
            if (dataset == null) return;
            for (int x = 0; x < dataset.GetLength(0); x++)
            {
                for (int y = 0; y < dataset.GetLength(1); y++)
                {
                    if (!dataset[x, y].IsEdge)
                        DieAllNum++;
                    if (dataset[x, y].ColorIndex == Die.DefaultOk)
                        DieOkNum++;
                    if (dataset[x, y].ColorIndex == Die.DefaultNg)
                        DieNgNum++;
                }
            }
        }

        /// <summary>
        /// 获取ok的Die个数
        /// </summary>
        /// <returns></returns>
        public int GetOkDieNum()
        {
            if (dataset == null) return 0;
            for (int x = 0; x < dataset.GetLength(0); x++)
            {
                for (int y = 0; y < dataset.GetLength(1); y++)
                {
                    if (dataset[x, y].ColorIndex == Die.DefaultOk)
                        DieOkNum++;
                }
            }
            return DieOkNum;
        }

        /// <summary>
        /// 获取Ng的die个数
        /// </summary>
        /// <returns></returns>
        public int GetNgDieNum()
        {
            if (dataset == null) return 0;
            for (int x = 0; x < dataset.GetLength(0); x++)
            {
                for (int y = 0; y < dataset.GetLength(1); y++)
                {
                    if (dataset[x, y].ColorIndex == Die.DefaultNg)
                        DieNgNum++;
                }
            }
            return DieNgNum;
        }

        private void registerEvents()
        {

            this.MouseMove += Wafermap_MouseMove;
            // Event to be registered
            if (interactive)
            {
                //this.MouseClick += Wafermap_MouseClick;
                this.MouseDown += Wafermap_MouseDown;
                this.MouseUp += Wafermap_MouseUp;
                //this.MouseDoubleClick += Wafermap_MouseDoubleClick;
                KeyDown += Wafermap_KeyDown;

                //darkSettionPanel.Visible = true;
            }
            else
            {
                this.MouseDown -= Wafermap_MouseDown;
                this.MouseUp -= Wafermap_MouseUp;
                //this.MouseMove -= Wafermap_MouseMove;
                KeyDown -= Wafermap_KeyDown;
            }
        }
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            double step = 1.05;//缩放倍率
            if (e.Delta > 0)
            {
                this.Height = (int)(this.Height * step);
                this.Width = (int)(this.Width * step);
                int px = e.X - this.Location.X;
                int py = e.Y - this.Location.Y;
                int px_add = (int)(px * (step - 1.0));
                int py_add = (int)(py * (step - 1.0));
                this.Location = new Point(this.Location.X - px_add, this.Location.Y - py_add);
            }
            else
            {
                this.Height = (int)(this.Height / step);
                this.Width = (int)(this.Width / step);
                int px = e.X - this.Location.X;
                int py = e.Y - this.Location.Y;
                int px_add = (int)(px * (1.0 - 1.0 / step));
                int py_add = (int)(py * (1.0 - 1.0 / step));
                this.Location = new Point(this.Location.X + px_add, this.Location.Y + py_add);
            }
            //Debug.WriteLine("asdsd");
            //this.Width += e.Delta;
            //this.Height += e.Delta;
            //假设你的鼠标指针坐标是(x,y)，而 test 在缩放前的左上角坐标是(u,v)，那么缩放之后的 test 的左上角的新坐标就是 (x-(u-x)*s, y-(v-y)*s)，这里的 s 就是缩放比率。
            //this.Location = new Point(Convert.ToInt32(e.X - (this.Location.X - e.X) * 0.1), Convert.ToInt32(e.Y - (this.Location.Y - e.Y) * 0.1));
        }
        protected override bool IsInputKey(Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Right:
                case Keys.Left:
                case Keys.Up:
                case Keys.Down:
                    return true;
            }
            return base.IsInputKey(keyData);
        }

        /// <summary>
        /// 键盘上下左右控制
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Wafermap_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData == Keys.Left)
            {
                SelectX--;
                if (DirectionOnlyNgDie) MoveLineNextNgDie(false);
            }
            else if (e.KeyData == Keys.Right)
            {
                SelectX++;
                if (DirectionOnlyNgDie) MoveLineNextNgDie();
            }
            else if (e.KeyData == Keys.Up)
            {
                SelectY--;
                if (DirectionOnlyNgDie) MoveLineFirstNgDie();
            }
            else if (e.KeyData == Keys.Down)
            {
                SelectY++;
                if (DirectionOnlyNgDie) MoveLineFirstNgDie();
            }
        }

        /// <summary>
        /// Y方向上移动到第一个NGDIe
        /// </summary>
        private void MoveLineFirstNgDie()
        {
            for (int x = 0; x < dataset.GetLength(0); x++)
            {
                if (dataset[x, SelectY].ColorIndex == Die.DefaultNg)
                {
                    SelectX = x;
                    break;
                }
            }
        }

        private void MoveLineNextNgDie(bool goRight = true)
        {
            if (goRight)
            {
                for (int x = SelectX; x < dataset.GetLength(0); x++)
                {
                    if (dataset[x, SelectY].ColorIndex == Die.DefaultNg)
                    {
                        SelectX = x;
                        break;
                    }
                }
            }
            else
            {
                for (int x = SelectX; x > 0; x--)
                {
                    if (dataset[x, SelectY].ColorIndex == Die.DefaultNg)
                    {
                        SelectX = x;
                        break;
                    }
                }
            }
        }


        /// <summary>
        /// 是否鼠标长按移动
        /// </summary>
        private bool isMouseHoldMove = false;
        /// <summary>
        /// 鼠标按下事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Wafermap_MouseDown(object sender, MouseEventArgs e)
        {
            // Basically the same as MouseMove, just a few other infos passed
            float x_coord = ((float)e.X - boundingBox_.X) / dieSize_.Width;
            float y_coord = ((float)e.Y - boundingBox_.Y) / dieSize_.Height;
            int x = (int)Math.Floor(x_coord);
            int y = (int)Math.Floor(y_coord);
            try
            {
                if (dataset == null) return;
                var pre = _SelectOneDie;
                _SelectOneDie = dataset[x, y];
                updateDie(pre, _SelectOneDie, false);

                if (e.Button == MouseButtons.Left)
                {
                    updateDie(pre, pre, false);
                    if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
                        DragMode = true;
                    SelectMode = false;
                    DragStartPoint.X = e.X;
                    DragStartPoint.Y = e.Y;
                    _selectStartDie = null;
                    _selectEndDie = null;

                    _SelectOneDie.MouseArgs = e;
                    _SelectX = x;
                    _SelectY = y;
                    if (OnDieClick != null) OnDieClick(this, dataset[x, y]);
                }
                else if (e.Button == MouseButtons.Right)
                {
                    SelectMode = true;
                    _SelectOneDie.ColorIndex = Die.DefaultUndo;
                    _SelectOneDie.IsEdge = false;
                    _SelectX = x;
                    _SelectY = y;
                    _selectStartDie = _SelectOneDie;
                }
                else if (e.Button == MouseButtons.Middle)
                { 
                    SelectMode = true;
                    _SelectOneDie.ColorIndex = Die.DefaultEdge;
                    _SelectOneDie.IsEdge = true;
                    _SelectX = x;
                    _SelectY = y;
                    _selectStartDie = _SelectOneDie;
                }

            }
            catch (Exception ex)
            {
                //System.Diagnostics.Debug.WriteLine("Not good click..");
                //throw ex;
            }
        }

        private int previousX = -1, previousY = -1;
        /// <summary>
        /// 鼠标移动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Wafermap_MouseMove(object sender, MouseEventArgs e)
        {
            // This one is going to be tricky
            // We need to calculate the die coordinates from screen coordinates
            // We have global vars boundingBox_ and dieSize_
            float x_coord = ((float)e.X - boundingBox_.X) / dieSize_.Width;
            float y_coord = ((float)e.Y - boundingBox_.Y) / dieSize_.Height;
            int x = (int)Math.Floor(x_coord);
            int y = (int)Math.Floor(y_coord);
            try
            {
                if (dataset != null && !DragMode)
                {
                    Die currentDie = dataset[x, y];
                    Die previousDie = null;
                    if (previousX != -1 && previousY != -1) previousDie = dataset[previousX, previousY];
                    updateDie(previousDie, currentDie);
                    if (previousX != x) previousX = x;
                    if (previousY != y) previousY = y;

                    if (dataset.GetLength(0) < 100 && dataset.GetLength(1) < 100 && IsShowTooltip && currentDie.Enabled)
                    {
                        string tip = string.Format("Y:{0} X:{1}", GetChangedYindex(currentDie.YIndex), GetChangedXindex(currentDie.XIndex));
                        if (TooltipFormat.StartsWith("X"))
                            tip = string.Format(TooltipFormat, GetChangedXindex(currentDie.XIndex), GetChangedYindex(currentDie.YIndex));
                        else if (TooltipFormat.StartsWith("Y"))
                            tip = string.Format(TooltipFormat, GetChangedYindex(currentDie.YIndex), GetChangedXindex(currentDie.XIndex));
                        toolTip1.Show(tip, this, new Point(e.X + 10, e.Y - 2));
                    }
                    else
                    {
                        toolTip1.Hide(this);
                    }
                }
                if (DragMode && e.Button == MouseButtons.Left) //鼠标左键拖动
                {
                    Point mousePositon = Control.MousePosition;
                    mousePositon.Offset(-DragStartPoint.X, -DragStartPoint.Y);
                    Point point = Parent.PointToClient(mousePositon);
                    Location = point;
                }
                else if (SelectMode)
                {
                    //Debug.WriteLine(string.Format("x: {0}, y: {1}", e.X, e.Y));
                    _selectEndDie = dataset[x, y];
                    if (_selectStartDie != _selectEndDie) isMouseHoldMove = true;
                    DrawSelectDies();
                }
            }
            catch (Exception er)
            {
                //System.Diagnostics.Debug.WriteLine("Not good move..");
            }
        }
        /// <summary>
        /// 鼠标抬起事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Wafermap_MouseUp(object sender, MouseEventArgs e)
        {
            // Basically the same as MouseMove, just a few other infos passed
            float x_coord = ((float)e.X - boundingBox_.X) / dieSize_.Width;
            float y_coord = ((float)e.Y - boundingBox_.Y) / dieSize_.Height;
            int x = (int)Math.Floor(x_coord);
            int y = (int)Math.Floor(y_coord);
            try
            {
                if (dataset == null) return;
                if (e.Button == MouseButtons.Left)
                {
                    DragMode = false;
                }
                else if (e.Button == MouseButtons.Right)
                {
                    isMouseHoldMove = false;
                    _selectEndDie = dataset[x, y];
                    if (_selectEndDie != _selectStartDie) { SelectOneDie = null; SelectX = -1; SelectY = -1; }
                    DrawSelectDies(1);
                    //if (OnMappingUpdate != null) OnMappingUpdate(this, dataset);
                }
                else if (e.Button == MouseButtons.Middle)
                {
                    isMouseHoldMove = false;
                    _selectEndDie = dataset[x, y];
                    DrawSelectDies(2);
                    //if (OnMappingUpdate != null) OnMappingUpdate(this, dataset);
                }
                SelectMode = false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Not good click..");
                //throw ex;
            }
        }


        /// <summary>
        /// 获取矩形左上角和右下角两个点
        /// </summary>
        /// <param name="startDie"></param>
        /// <param name="endDie"></param>
        /// <returns></returns>
        private Die[] GetLeftTopAndRightBottomDie(Die startDie, Die endDie)
        {
            Die[] dies = new Die[2];
            if (endDie.XIndex >= startDie.XIndex) // end的X在start的右边
            {
                if (endDie.YIndex >= startDie.YIndex) // 那么end是右下角那个点
                {
                    dies[0] = startDie;
                    dies[1] = endDie;

                }
                else // end是右上角那个点
                {
                    int topLeftX = startDie.XIndex;
                    int topLeftY = endDie.YIndex;
                    int bottomRightX = endDie.XIndex;
                    int bottomRightY = startDie.YIndex;
                    dies[0] = dataset[topLeftX, topLeftY];
                    dies[1] = dataset[bottomRightX, bottomRightY];
                }
            }
            else
            {
                if (endDie.YIndex >= startDie.YIndex) // 那么end是左下角那个点
                {
                    int topLeftX = endDie.XIndex;
                    int topLeftY = startDie.YIndex;
                    int bottomRightX = startDie.XIndex;
                    int bottomRightY = endDie.YIndex;
                    dies[0] = dataset[topLeftX, topLeftY];
                    dies[1] = dataset[bottomRightX, bottomRightY];
                }
                else // end是左上角那个点
                {
                    dies[0] = endDie;
                    dies[1] = startDie;
                }
            }
            return dies;
        }

        #region 用于局部更新绘制
        Die previosSelectStartDie = null, previosSelectEndDie = null;

        private void cbMouseEnable_CheckedChanged(object sender, EventArgs e)
        {
            Interactive = cbMouseEnable.Checked;
        }
        #endregion

        /// <summary>
        /// 实时绘制选中的dies
        /// </summary>
        /// <param name="showMode">选中区域显示类型{0:不显示 1:芯片区域 2:非芯片区域}</param>
        private void DrawSelectDies(int showMode = 0)
        {
            if (!_SelectMultiple) return;
            if (_selectEndDie == null || _selectStartDie == null) return;
            if (previosSelectStartDie == null) previosSelectStartDie = _selectStartDie;
            if (previosSelectEndDie == null) previosSelectEndDie = _selectEndDie;
            //if (_selectStartDie.XIndex == _selectEndDie.XIndex && _selectStartDie.YIndex == _selectEndDie.YIndex) { return; }

            //SelectMode = false;
            updateDie(null, SelectOneDie, false);
            Die[] dies = GetLeftTopAndRightBottomDie(previosSelectStartDie, previosSelectEndDie);
            if (showMode > 0)
            {
                for (int xIndex = dies[0].XIndex; xIndex <= dies[1].XIndex; xIndex++)
                {
                    for (int yIndex = dies[0].YIndex; yIndex <= dies[1].YIndex; yIndex++)
                    {
                        dataset[xIndex, yIndex].ColorIndex = showMode == 1 ? Die.DefaultUndo : Die.DefaultEdge;
                        dataset[xIndex, yIndex].IsEdge = showMode == 1 ? false : true;
                    }
                }
            }
            if (dies.Length < 2) return;
            Point positionSelect = new Point(Convert.ToInt32(boundingBox_.X + (float)dies[0].XIndex * dieSize_.Width - 1), Convert.ToInt32(boundingBox_.Y + (float)dies[0].YIndex * dieSize_.Height - 1));
            Rectangle dieSelect = new Rectangle(positionSelect, new Size(Convert.ToInt32((dies[1].XIndex - dies[0].XIndex + 1) * dieSize_.Width + 2), Convert.ToInt32((dies[1].YIndex - dies[0].YIndex + 1) * dieSize_.Height + 2)));
            dieSelect.Inflate(Convert.ToInt32(dieSize_.Width) + 10, Convert.ToInt32(dieSize_.Height) + 10);
            Invalidate(dieSelect); //, Convert.ToInt32(endPosition.X), Convert.ToInt32(die.Height)));

            previosSelectStartDie = _selectStartDie;
            previosSelectEndDie = _selectEndDie;
            dies = GetLeftTopAndRightBottomDie(previosSelectStartDie, previosSelectEndDie);
            if (dies.Length < 2) return;
            positionSelect = new Point(Convert.ToInt32(boundingBox_.X + (float)dies[0].XIndex * dieSize_.Width - 1), Convert.ToInt32(boundingBox_.Y + (float)dies[0].YIndex * dieSize_.Height - 1));
            dieSelect = new Rectangle(positionSelect, new Size(Convert.ToInt32((dies[1].XIndex - dies[0].XIndex + 1) * dieSize_.Width + 2), Convert.ToInt32((dies[1].YIndex - dies[0].YIndex + 1) * dieSize_.Height + 2)));
            dieSelect.Inflate(Convert.ToInt32(dieSize_.Width) + 10, Convert.ToInt32(dieSize_.Height) + 10);
            Invalidate(dieSelect); //, Convert.ToInt32(endPosition.X), Convert.ToInt32(die.Height)));
        }

        Pen dieMoveingPen = new Pen(Color.Black);

        /// <summary>
        /// 晶圆上下左右移动的时候移除当前的选中
        /// </summary>
        /// <param name="previosDie"></param>
        private void updateTDLR(Die die)
        {
            if (die == null||die.IsEdge) return;
            Graphics g = this.CreateGraphics();
            g.SmoothingMode = SmoothingMode.HighSpeed;
            Color previousFill = Color.FromArgb(_DieAlpha, colors[die.ColorIndex]);
            PointF previousPosition = new PointF(boundingBox_.X + (float)die.XIndex * dieSize_.Width, boundingBox_.Y + (float)die.YIndex * dieSize_.Height);
            RectangleF pDieRect = new RectangleF(previousPosition, dieSize_);
            g.FillRectangle(new SolidBrush(previousFill), pDieRect);
            g.DrawRectangle(dieOutlinePen, pDieRect.X, pDieRect.Y, pDieRect.Width, pDieRect.Height);
            pDieRect.Inflate(dieSize_.Width*2, dieSize_.Height*2);
            Invalidate(new Rectangle(Convert.ToInt32(pDieRect.X), Convert.ToInt32(pDieRect.Y), Convert.ToInt32(pDieRect.Width), Convert.ToInt32(pDieRect.Height)));
        }

        // This method should be used to change die coloring of a bin directly
        // This is needed to avoid redraws when not neccessary
        // The updated bins are filled with higher alpha to highlight them
        /// <summary>
        /// 移动的时候显示
        /// </summary>
        /// <param name="previousX"></param>
        /// <param name="previousY"></param>
        /// <param name="previousBincode"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="bincode"></param>
        private void updateDie(Die previosDie, Die currentDie, bool isMove = true)
        {
            if (previosDie == null && currentDie == null) return;
            if (currentDie == null) return;
            PointF position = new PointF(boundingBox_.X + (float)currentDie.XIndex * dieSize_.Width, boundingBox_.Y + (float)currentDie.YIndex * dieSize_.Height);
            RectangleF die = new RectangleF(position, dieSize_);
            if (currentDie.IsEdge) return;
            if (isMove && previosDie != null && previousX != -1 && previousY != -1 && (previousX != _SelectX || previousY != _SelectY)) // 加了！=selectX 主要是防止已经选中的划过会出现白边框
            {
                //Graphics g = this.CreateGraphics();
                //g.SmoothingMode = SmoothingMode.HighSpeed;
                Color previousFill = Color.FromArgb(_DieAlpha, colors[previosDie.ColorIndex]);
                PointF previousPosition = new PointF(boundingBox_.X + (float)previousX * dieSize_.Width, boundingBox_.Y + (float)previousY * dieSize_.Height);
                RectangleF pDieRect = new RectangleF(previousPosition, dieSize_);
                //g.FillRectangle(new SolidBrush(previousFill), pDieRect);
                //g.DrawRectangle(dieOutlinePen, pDieRect.X, pDieRect.Y, pDieRect.Width, pDieRect.Height);
                pDieRect.Inflate(dieSize_.Width, dieSize_.Height);
                Invalidate(new Rectangle(Convert.ToInt32(pDieRect.X), Convert.ToInt32(pDieRect.Y), Convert.ToInt32(pDieRect.Width), Convert.ToInt32(pDieRect.Height)));
            }
            else if (previosDie != null)
            {
                PointF previousPosition = new PointF(boundingBox_.X + (float)previousX * dieSize_.Width, boundingBox_.Y + (float)previousY * dieSize_.Height);
                RectangleF pDieRect = new RectangleF(previousPosition, dieSize_); 
                pDieRect.Inflate(20, 20);
                Invalidate(new Rectangle(Convert.ToInt32(pDieRect.X), Convert.ToInt32(pDieRect.Y), Convert.ToInt32(pDieRect.Width), Convert.ToInt32(pDieRect.Height)));
            }
            Rectangle rectangle = new Rectangle(Convert.ToInt32(die.X), Convert.ToInt32(die.Y), Convert.ToInt32(die.Width), Convert.ToInt32(die.Height));
            rectangle.Inflate(20, 20);
            Invalidate(rectangle);
        }


        private string[] alpha = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
        /// <summary>
        /// 获取X的转换坐标
        /// </summary>
        /// <param name="xindex"></param>
        /// <returns></returns>
        public string GetChangedXindex(int xindex = -1)
        {
            int changeindex = xindex == -1 ? SelectX - OffsetX : xindex - OffsetX;
            string res = changeindex.ToString();
            if (dataset.GetLength(0) <= 36 && changeindex > 9)
            {
                res = alpha[changeindex - 9 - 1];
            }
            return res;
        }
        /// <summary>
        /// 获取Y的转换坐标
        /// </summary>
        /// <param name="yindex"></param>
        /// <returns></returns>
        public string GetChangedYindex(int yindex = -1)
        {
            int changeindex = yindex == -1 ? SelectY - OffsetY : yindex - OffsetY;
            string res = changeindex.ToString();
            if (dataset.GetLength(0) <= 36 && changeindex > 9)
            {
                res = alpha[changeindex - 9 - 1];
            }
            return res;
        }

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
            this.darkSettionPanel = new YiNing.UI.Controls.DarkSectionPanel();
            this.cbMouseEnable = new System.Windows.Forms.CheckBox();
            this.darkLabel6 = new YiNing.UI.Controls.DarkLabel();
            this.darkLabel5 = new YiNing.UI.Controls.DarkLabel();
            this.darkLabel4 = new YiNing.UI.Controls.DarkLabel();
            this.darkLabel3 = new YiNing.UI.Controls.DarkLabel();
            this.darkLabel2 = new YiNing.UI.Controls.DarkLabel();
            this.darkLabel1 = new YiNing.UI.Controls.DarkLabel();
            this.darkSettionPanel.SuspendLayout();
            this.SuspendLayout();
            // 
            // toolTip1
            // 
            this.toolTip1.AutoPopDelay = 1000;
            this.toolTip1.InitialDelay = 500;
            this.toolTip1.ReshowDelay = 100;
            // 
            // darkSettionPanel
            // 
            this.darkSettionPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.darkSettionPanel.Controls.Add(this.cbMouseEnable);
            this.darkSettionPanel.Controls.Add(this.darkLabel6);
            this.darkSettionPanel.Controls.Add(this.darkLabel5);
            this.darkSettionPanel.Controls.Add(this.darkLabel4);
            this.darkSettionPanel.Controls.Add(this.darkLabel3);
            this.darkSettionPanel.Controls.Add(this.darkLabel2);
            this.darkSettionPanel.Location = new System.Drawing.Point(3, 419);
            this.darkSettionPanel.Name = "darkSettionPanel";
            this.darkSettionPanel.SectionHeader = "鼠标操作";
            this.darkSettionPanel.Size = new System.Drawing.Size(92, 115);
            this.darkSettionPanel.TabIndex = 1;
            // 
            // cbMouseEnable
            // 
            this.cbMouseEnable.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.cbMouseEnable.AutoSize = true;
            this.cbMouseEnable.Checked = true;
            this.cbMouseEnable.CheckState = System.Windows.Forms.CheckState.Checked;
            this.cbMouseEnable.Location = new System.Drawing.Point(58, 5);
            this.cbMouseEnable.Name = "cbMouseEnable";
            this.cbMouseEnable.Size = new System.Drawing.Size(15, 14);
            this.cbMouseEnable.TabIndex = 6;
            this.cbMouseEnable.UseVisualStyleBackColor = true;
            this.cbMouseEnable.CheckedChanged += new System.EventHandler(this.cbMouseEnable_CheckedChanged);
            // 
            // darkLabel6
            // 
            this.darkLabel6.BackColor = System.Drawing.Color.Transparent;
            this.darkLabel6.ForeColor = System.Drawing.Color.DarkGray;
            this.darkLabel6.Location = new System.Drawing.Point(5, 95);
            this.darkLabel6.Name = "darkLabel6";
            this.darkLabel6.Size = new System.Drawing.Size(83, 21);
            this.darkLabel6.TabIndex = 4;
            this.darkLabel6.Text = "Ctrl+左键移动";
            // 
            // darkLabel5
            // 
            this.darkLabel5.AutoSize = true;
            this.darkLabel5.BackColor = System.Drawing.Color.Transparent;
            this.darkLabel5.ForeColor = System.Drawing.Color.DarkGray;
            this.darkLabel5.Location = new System.Drawing.Point(17, 77);
            this.darkLabel5.Name = "darkLabel5";
            this.darkLabel5.Size = new System.Drawing.Size(53, 12);
            this.darkLabel5.TabIndex = 3;
            this.darkLabel5.Text = "滚轮缩放";
            // 
            // darkLabel4
            // 
            this.darkLabel4.AutoSize = true;
            this.darkLabel4.BackColor = System.Drawing.Color.Transparent;
            this.darkLabel4.ForeColor = System.Drawing.Color.Green;
            this.darkLabel4.Location = new System.Drawing.Point(17, 59);
            this.darkLabel4.Name = "darkLabel4";
            this.darkLabel4.Size = new System.Drawing.Size(53, 12);
            this.darkLabel4.TabIndex = 2;
            this.darkLabel4.Text = "右键新增";
            // 
            // darkLabel3
            // 
            this.darkLabel3.AutoSize = true;
            this.darkLabel3.BackColor = System.Drawing.Color.Transparent;
            this.darkLabel3.ForeColor = System.Drawing.Color.Red;
            this.darkLabel3.Location = new System.Drawing.Point(17, 42);
            this.darkLabel3.Name = "darkLabel3";
            this.darkLabel3.Size = new System.Drawing.Size(53, 12);
            this.darkLabel3.TabIndex = 1;
            this.darkLabel3.Text = "中键删除";
            // 
            // darkLabel2
            // 
            this.darkLabel2.AutoSize = true;
            this.darkLabel2.BackColor = System.Drawing.Color.Transparent;
            this.darkLabel2.ForeColor = System.Drawing.Color.Chocolate;
            this.darkLabel2.Location = new System.Drawing.Point(17, 25);
            this.darkLabel2.Name = "darkLabel2";
            this.darkLabel2.Size = new System.Drawing.Size(53, 12);
            this.darkLabel2.TabIndex = 0;
            this.darkLabel2.Text = "左键选择";
            // 
            // darkLabel1
            // 
            this.darkLabel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.darkLabel1.AutoSize = true;
            this.darkLabel1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(220)))), ((int)(((byte)(220)))));
            this.darkLabel1.Location = new System.Drawing.Point(18, 499);
            this.darkLabel1.Name = "darkLabel1";
            this.darkLabel1.Size = new System.Drawing.Size(0, 12);
            this.darkLabel1.TabIndex = 0;
            // 
            // Wafermap
            // 
            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(63)))), ((int)(((byte)(65)))));
            this.Controls.Add(this.darkSettionPanel);
            this.Controls.Add(this.darkLabel1);
            this.Name = "Wafermap";
            this.Size = new System.Drawing.Size(539, 537);
            this.darkSettionPanel.ResumeLayout(false);
            this.darkSettionPanel.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

    }
}
